#include <stdio.h>
#include <sys/time.h>
#include "model.h"
#include "channel.h"
#include "redis.h"
#include "value.h"
#include "sched_pub.h"
#include "z_logger.h"

static segment_e segments[] = {seg_do, seg_di, seg_ao, seg_ai};

void check_segment(pub_handler_t *handler, void *filter_args, device_t *device, segment_e segment) {
    vector_t *local_key_list = &device->_product->thing_model[segment];
    vector_t *local_val_list = &device->thing_value[segment];

    vector_t remote_key_list = vector_initializer;
    vector_t remote_val_list = vector_initializer;

    for (int i_local = 0; i_local < vector_size(local_key_list); ++i_local) {
        thing_model_t *local_key = vector_get(local_key_list, i_local);
        if (local_key->segment == segment &&
            (!handler->on_filter || handler->on_filter(local_key, filter_args))) {
            vector_add(&remote_key_list, local_key);
        }
    }

    redis_get_values(device, &remote_key_list, &remote_val_list);

    //和redis比较
    for (int i_local = 0; i_local < vector_size(local_key_list); ++i_local) {
        thing_model_t *local_key = vector_get(local_key_list, i_local);
        value_t *local_val = vector_get(local_val_list, i_local);

        for (int i_remote = 0; i_remote < vector_size(&remote_key_list); ++i_remote) {
            thing_model_t *remote_key = vector_get(&remote_key_list, i_remote);
            if (local_key->super.id == remote_key->super.id) {
                value_t *remote_val = vector_get(&remote_val_list, i_remote);

                //如果数据有变
                if (!handler->on_compare ||
                    handler->on_compare(local_val, remote_val, remote_key->valid_max, remote_key->valid_min)) {
                    //复制数据
                    value_copy(local_val, remote_val);
                    //设置变更标志
                    local_val->_changed = true;
                }

                break;
            }
        }
    }

    vector_clear(&remote_key_list);
    vector_foreach(&remote_val_list, (vector_foreach_callback) value_free);
    vector_clear(&remote_val_list);
}

void check_device(pub_handler_t *handler, void *filter_args, device_t *device) {
    for (int i = 0; i < sizeof(segments) / sizeof(segments[0]); ++i) {
        check_segment(handler, filter_args, device, segments[i]);
    }
}

void check_channel(pub_handler_t *handler, void *filter_args, channel_t *channel) {
    for (int i = 0; i < vector_size(&channel->devices); ++i) {
        device_t *device = vector_get(&channel->devices, i);

        check_device(handler, filter_args, device);
    }
}

void check_next_sched(pub_handler_t *handler, seqiot_t *seqiot, time_t timestamp) {
    for (int i_cat = 0; i_cat < vector_size(&seqiot->catalogs); ++i_cat) {
        data_catalog_t *catalog = vector_get(&seqiot->catalogs, i_cat);

        if (catalog->_next_sched && catalog->_next_sched <= timestamp) {
            catalog->_next_sched = next_sched(timestamp, &catalog->pub);

            struct tm _tm;
            localtime_r(&catalog->_next_sched, &_tm);
            log_debug("sched=%04d-%02d-%02d %02d:%02d:%02d, catalog=%d, period=%d, delay=%d",
                      _tm.tm_year + 1900, _tm.tm_mon + 1, _tm.tm_mday, _tm.tm_hour, _tm.tm_min, _tm.tm_sec,
                      catalog->catalog, catalog->pub.period, catalog->pub.delay);

            for (int i_chn = 0; i_chn < vector_size(&seqiot->channels); ++i_chn) {
                channel_t *channel = vector_get(&seqiot->channels, i_chn);

                check_channel(handler, &catalog->catalog, channel);
            }
        }
    }
}

void check_whole(pub_handler_t *handler, seqiot_t *seqiot) {
    for (int i_chn = 0; i_chn < vector_size(&seqiot->channels); ++i_chn) {
        channel_t *channel = vector_get(&seqiot->channels, i_chn);

        check_channel(handler, NULL, channel);
    }
}

void publish_changed(pub_handler_t *handler, seqiot_t *seqiot) {
    for (int i_chn = 0; i_chn < vector_size(&seqiot->channels); ++i_chn) {
        channel_t *channel = vector_get(&seqiot->channels, i_chn);

        for (int i_dev = 0; i_dev < vector_size(&channel->devices); ++i_dev) {
            device_t *device = vector_get(&channel->devices, i_dev);
            if (device->channel == channel->super.id) {
                for (int i_seg = 0; i_seg < sizeof(segments) / sizeof(segments[0]); ++i_seg) {
                    handler->on_write(handler, device, segments[i_seg]);
                }
            }
        }
    }

    handler->on_flush(handler);
}